package com.siruier.boss.ui.helper

import android.Manifest
import android.content.Context
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.tencent.bugly.crashreport.CrashReport
import com.yanzhenjie.permission.AndPermission
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import android.location.LocationManager
import android.content.Intent
import android.provider.Settings
import com.siruier.boss.api.core.FirmException
import com.siruier.boss.api.core.launchUI
import com.siruier.boss.ui.api.ApiObserver
import com.siruier.boss.ui.base.BaseActivity
import com.siruier.boss.ui.dialog.showAlertDialog
import com.siruier.boss.ui.ext.permissionRequest


typealias OnLocationChange = (aMapLocation: AMapLocation) -> Unit

object LocationHelper : DefaultLifecycleObserver, AMapLocationListener {
    private const val PERMISSION_TIPS = "该功能需要定位才能使用，如果你定位权限拒绝将无法使用。"
    private const val PERMISSION_DENIED_MESSAGE = "定位权限没有开启，无法加载数据，\n点击去授权同意开启。"
    private val MANIFEST = arrayOf(
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACCESS_FINE_LOCATION
    )

    internal val locationChange: MutableList<LocationLifecycleObserver> = mutableListOf()
    private var continuation: Continuation<AMapLocation?>? = null
    private var activity: BaseActivity<*>? = null
    private var mLocationClient: AMapLocationClient? = null
    private var isStarted: Boolean = false
    var aMapLocation: AMapLocation? = null

    fun BaseActivity<*>.initLocation() {
        activity = this
        lifecycle.addObserver(LocationHelper)
        AMapLocationClient.updatePrivacyShow(application, true, true)
        AMapLocationClient.updatePrivacyAgree(application, true)
        mLocationClient = AMapLocationClient(application)
            .apply {
                setLocationOption(AMapLocationClientOption().apply {
                    locationPurpose = AMapLocationClientOption.AMapLocationPurpose.SignIn
                    isOnceLocation = true
                })
                setLocationListener(LocationHelper)
            }
        startLocation()
    }

    private fun BaseActivity<*>.startLocation() {
        if (isStarted) {
            return
        }
        isStarted = true
        gpsOpen {
            if (AndPermission.hasPermissions(this, MANIFEST)) {
                doStartLocation()
            } else {
                showAlertDialog {
                    message(message = PERMISSION_TIPS)
                    mCancelable = false
                    negativeButton(name = "不申请") {
                        resumeWithException(PERMISSION_DENIED_MESSAGE)
                    }
                    positiveButton(name = "去申请") {
                        doStartLocation()
                    }
                    closeCallback = { resumeWithException(PERMISSION_DENIED_MESSAGE) }
                }
            }
        }
    }

    private fun doStartLocation() {
        activity?.permissionRequest {
            permissionArray(MANIFEST)
            onGranted {
                mLocationClient?.stopLocation()
                mLocationClient?.startLocation()
            }
            onDenied {
                resumeWithException(PERMISSION_DENIED_MESSAGE)
            }
        }
    }

    suspend fun BaseActivity<*>.loadMapLocation() = suspendCancellableCoroutine<AMapLocation?> { coroutine ->
        if (aMapLocation != null) {
            coroutine.resume(aMapLocation)
        } else {
            coroutine.invokeOnCancellation {
                continuation = null
                isStarted = false
            }
            continuation = coroutine
        }
        if (!isStarted) {
            startLocation()
        }
    }

    private fun resumeWithException(errorMessage: String) {
        continuation?.resumeWithException(FirmException(errorMessage))
        continuation = null
        isStarted = false
    }

    override fun onLocationChanged(amapLocation: AMapLocation?) {
        if (amapLocation?.errorCode == 0) {
            this.aMapLocation = amapLocation
            continuation?.resume(amapLocation)
            notifyForegroundChange(amapLocation)
        } else {
            resumeWithException("定位失败")
            if (amapLocation == null) {
                CrashReport.postCatchedException(RuntimeException("定位返回null"))
            } else {
                CrashReport.postCatchedException(
                    RuntimeException(
                        "errorCode==>${amapLocation.errorCode}&errorInfo==>${amapLocation.errorInfo}"
                    )
                )
            }
        }
        mLocationClient?.stopLocation()
    }

    fun BaseActivity<*>.observeLocation(owner: LifecycleOwner, onLocationChange: OnLocationChange) {
        if (aMapLocation == null) {
            launchUI({ onLocationChange.invoke(loadMapLocation()!!) }, ApiObserver())
        } else {
            onLocationChange.invoke(aMapLocation!!)
        }
        val mLocationLifecycleObserver = LocationLifecycleObserver(onLocationChange)
        owner.lifecycle.addObserver(mLocationLifecycleObserver)
        locationChange.add(mLocationLifecycleObserver)
    }

    private fun notifyForegroundChange(aMapLocation: AMapLocation) {
        locationChange.takeIf { it.size > 0 }?.forEach {
            kotlin.runCatching { it.onLocationChange(aMapLocation) }
        }
    }

    private fun BaseActivity<*>.gpsOpen(callback: () -> Unit) {
        if (!isGpsOpen(this)) {
            showAlertDialog {
                message(message = PERMISSION_TIPS)
                mCancelable = false
                negativeButton(name = "不打开") {
                    resumeWithException(PERMISSION_DENIED_MESSAGE)
                }
                positiveButton(name = "去打开GPS") {
                    launchStartActivityForResult(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), isNeedResultOk = false) {
                        if (isGpsOpen(this@gpsOpen)) {
                            callback.invoke()
                        } else {
                            resumeWithException(PERMISSION_DENIED_MESSAGE)
                        }
                    }
                }
                closeCallback = { resumeWithException(PERMISSION_DENIED_MESSAGE) }
            }
        } else {
            callback.invoke()
        }
    }

    private fun isGpsOpen(context: Context): Boolean {
        val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
        // 通过GPS卫星定位，定位级别可以精确到街（通过24颗卫星定位，在室外和空旷的地方定位准确、速度快）
        val gps = locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER)
        // 通过WLAN或移动网络(3G/2G)确定的位置（也称作AGPS，辅助GPS定位。主要用于在室内或遮盖物（建筑群或茂密的深林等）密集的地方定位）
        val network = locationManager?.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        return gps == true || network == true
    }

    override fun onDestroy(owner: LifecycleOwner) {
        isStarted = false
        mLocationClient = null
        activity?.lifecycle?.removeObserver(this)
        mLocationClient?.stopLocation()
        mLocationClient?.onDestroy()
    }
}

internal class LocationLifecycleObserver(private var onLocationChange: OnLocationChange? = null) : DefaultLifecycleObserver {
    fun onLocationChange(aMapLocation: AMapLocation) = onLocationChange?.invoke(aMapLocation)
    override fun onDestroy(owner: LifecycleOwner) {
        onLocationChange = null
        LocationHelper.locationChange.remove(this)
    }
}